﻿using BCCommon;
using BCCommon.Enums;
using BCData.Common.Dictionary;
using BCData.Common.IP;
using BCData.Sim.Admin.Admin;
using BCData.Sim.Admin.StaffOrganizationMappingRecord;
using BCData.Sim.Company.Company;
using BCData.Sim.Company.Department;
using BCData.Sim.Company.JobTitle;
using BCData.Sim.Company.Position;
using BCDto.Common.IP;
using BCDto.Sim.Admin.Admin;
using BCDto.Sim.Company.Company;
using BCDto.Sim.Company.Department;
using BCEntity.Common.IP;
using BCEntity.Sim.Admin.Admin;
using BCService.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using WeChatSDK.Common;

namespace BCService.Sim.Admin.Admin
{
    public class AdminService : IAdminService
    {
        private readonly IAdminData adminData;
        private readonly IIPAddressRecordData ipAddressRecordData;
        private readonly ICompanyData companyData;
        private readonly IDepartmentData departmentData;
        private readonly IPositionData positionData;
        private readonly IJobTitleData jobTitleData;
        private readonly IStaffOrganizationMappingRecordData staffOrganizationMappingRecordData;
        public AdminService(
            IAdminData adminData, 
            IIPAddressRecordData ipAddressRecordData, 
            ICompanyData companyData, 
            IDepartmentData departmentData,
            IPositionData positionData,
            IJobTitleData jobTitleData,
            IStaffOrganizationMappingRecordData staffOrganizationMappingRecordData
            )
        {
            this.adminData = adminData;
            this.ipAddressRecordData = ipAddressRecordData;
            this.companyData = companyData;
            this.departmentData = departmentData;
            this.positionData = positionData;
            this.jobTitleData = jobTitleData;
            this.staffOrganizationMappingRecordData = staffOrganizationMappingRecordData;
        }

        public bool CheckAdminExists(string loginName)
        {
            return this.adminData.CheckAdminExists(loginName).GetAwaiter().GetResult();
        }
        
        public AdminDto Add(AdminRequestDto adminRequestDto, string ip)
        {
            if (this.adminData.CheckAdminExists(adminRequestDto.LoginName).GetAwaiter().GetResult())
            {
                throw new ArgumentException("此登录名称已存在。");
            }
            
            adminRequestDto.Password = adminRequestDto.Password.SHA256(adminRequestDto.LoginName);
            IPAddressRecordEntity iPAddressRecordEntity = new IPAddressRecordDto() { StartIP = ip }.As<IPAddressRecordEntity>();
            AdminEntity entity = adminRequestDto.As<AdminEntity>();
            IPAddressRecordEntity iPAddressRecordEntityResult = ipAddressRecordData.Get(iPAddressRecordEntity);
            entity.LogonIp = ip;
            entity.AddressIp = iPAddressRecordEntityResult != null ? iPAddressRecordEntityResult.IANA : "未知IP地址";
            entity.Avatar = "/assets/image/default_avatar.png";
           
            var jobTitle = this.jobTitleData.GetEntity(adminRequestDto.JobTitleKey).GetAwaiter().GetResult();
            if (jobTitle == null)
            {
                throw new ArgumentException("此职位名称不存在,请重试!");
            }
            var JobDuty = this.positionData.GetEntity(adminRequestDto.CompanyId,adminRequestDto.DepartmentId, adminRequestDto.JobDutyKey).GetAwaiter().GetResult();
            if (JobDuty == null)
            {
                throw new ArgumentException("此职务名称不存在,请重试!");
            }
            entity.JobTitle = jobTitle.JobTitle;
            entity.JobTitleKey = jobTitle.JobTitleNo;
            entity.JobDuty = JobDuty.PositionName;
            entity.JobDutyKey = JobDuty.PositionNo;
            entity.CompanyId = JobDuty.CompanyId;
            entity.CompanyName = JobDuty.CompanyName;
            entity.DepartmentId = JobDuty.DepartmentId;
            entity.DepartmentName = JobDuty.DepartmentName;
            var result = this.adminData.Add(entity).GetAwaiter().GetResult();

            if (result == null)
            {
                throw new ArgumentException("创建账号失败,请重试!");
            }

            return result.As<AdminDto>();
        }
        
        public AdminDto GetAdminInfoByAdminId(long adminId)
        {
            return this.adminData.GetAdmin(adminId).GetAwaiter().GetResult().As<AdminDto>();
        }

        public AdminDto GetNonePasswordAdminInfoByAdminId(long adminId)
        {
            var result = this.adminData.GetAdmin(adminId).GetAwaiter().GetResult();
            result.Password = null;
            return result.As<AdminDto>();
        }
        public AdminDto GetNonePasswordAdminInfoByAdminId(long adminId,AdminDto adminDto)
        {
            var result = this.adminData.GetAdmin(adminId).GetAwaiter().GetResult();
            result.Password = null;
            var staffMappingList = this.staffOrganizationMappingRecordData.GetList(adminId).GetAwaiter().GetResult();
            if(staffMappingList.Any(p=>p.CompanyId == adminDto.CompanyId&&p.DepartmentId == adminDto.DepartmentId))
            {
                var staffInfo = staffMappingList.Single(p => p.CompanyId == adminDto.CompanyId && p.DepartmentId == adminDto.DepartmentId);
                result.CompanyId = staffInfo.CompanyId;
                result.CompanyName = staffInfo.CompanyName;
                result.DepartmentId = staffInfo.DepartmentId;
                result.DepartmentName = staffInfo.DepartmentName;
                result.JobDuty = staffInfo.JobDuty;
                result.JobDutyKey = staffInfo.JobDutyKey;
                result.JobTitle = staffInfo.JobTitle;
                result.JobTitleKey = staffInfo.JobTitleKey;
            }
            return result.As<AdminDto>();
        }

        public AdminDto GetAdminInfoByLoginName(string loginName)
        {
            return this.adminData.GetAdmin(loginName).GetAwaiter().GetResult().As<AdminDto>();
        }
        
        public PageableList<AdminDto> GetAdmins(int? companyId, int? departmentId, string loginName, string fullName, AccountStatus? accountStatus, string sortName, bool? ascending, int pageIndex = 1, int pageSize = 10)
        {
            var list = this.adminData.GetAdmins(companyId, departmentId, loginName, fullName, accountStatus,sortName, ascending, pageIndex, pageSize).GetAwaiter().GetResult();

            return new PageableList<AdminDto>
            {
                Count = list.Item2,
                Items = list.Item1.As<IEnumerable<AdminDto>>()
            };
        }
        
        public AdminDto Logon(string userName, string password, string ip)
        {
            if (!this.adminData.CheckAdminExists(userName).GetAwaiter().GetResult())
            {
                throw new ArgumentException("用户不存在。");
            }

            AdminEntity entity = this.adminData.GetAdmin(userName).GetAwaiter().GetResult();
            
#if DEBUG
            if (password.SHA256(userName) != entity.Password)
            {
                throw new ArgumentException("用户密码不正确。");
            }
#else
            string pwd = AESUtils.AESDecrypt(password);
            if (pwd.SHA256(userName) != entity.Password)
            {
                throw new ArgumentException("用户密码不正确。");
            }
#endif
            IPAddressRecordEntity iPAddressRecordEntity = new IPAddressRecordDto() { StartIP = ip }.As<IPAddressRecordEntity>();
            IPAddressRecordEntity iPAddressRecordEntityResult = ipAddressRecordData.Get(iPAddressRecordEntity);
            entity.LogonIp = ip;
            entity.AddressIp = iPAddressRecordEntityResult != null ? iPAddressRecordEntityResult.IANA : "未知IP地址";
            this.adminData.UpdateAdminLogonInfo(entity);

            return entity.As<AdminDto>();
        }
        
        public AdminDto Update(AdminPutDto adminPutDto)
        {
            if (!this.adminData.CheckAdminExists(adminPutDto.AdminId).GetAwaiter().GetResult())
            {
                throw new ArgumentException("此员工不存在。");
            }
            AdminEntity entity = this.adminData.GetAdmin(adminPutDto.AdminId).GetAwaiter().GetResult();
            if (!string.IsNullOrWhiteSpace(adminPutDto.Password))
            {
                if (adminPutDto.Password.Length < 8 || adminPutDto.Password.Length > 16)
                {
                    throw new ArgumentException("长度为 8 到 16 个字符。");
                }
                Regex regex = new Regex(RegexPatterns.PASSWORD);
                if (!regex.IsMatch(adminPutDto.Password))
                {
                    throw new ArgumentException("密码需包含字母和数字。");
                }
                entity.Password = adminPutDto.Password.SHA256(entity.LoginName);
            }
            var jobTitle = this.jobTitleData.GetEntity(adminPutDto.JobTitleKey).GetAwaiter().GetResult();
            if (jobTitle == null)
            {
                throw new ArgumentException("此职位名称不存在,请重试!");
            }
            var JobDuty = this.positionData.GetEntity(adminPutDto.CompanyId, adminPutDto.DepartmentId, adminPutDto.JobDutyKey).GetAwaiter().GetResult();
            if (JobDuty == null)
            {
                throw new ArgumentException("此职务名称不存在,请重试!");
            }
            AdminEntity putEntity = adminPutDto.As<AdminEntity>();
            putEntity.Password = entity.Password;
            putEntity.LoginName = entity.LoginName;
            putEntity.JobTitle = jobTitle.JobTitle;
            putEntity.JobTitleKey = jobTitle.JobTitleNo;
            putEntity.JobDuty = JobDuty.PositionName;
            putEntity.JobDutyKey = JobDuty.PositionNo;
            putEntity.CompanyId = JobDuty.CompanyId;
            putEntity.CompanyName = JobDuty.CompanyName;
            putEntity.DepartmentId = JobDuty.DepartmentId;
            putEntity.DepartmentName = JobDuty.DepartmentName;
            return this.adminData.Update(putEntity).GetAwaiter().GetResult().As<AdminDto>();
        }
        
        public bool UpdateSelfPassword(long adminId, AdminCurrentPutDto dto)
        {
            if (!this.adminData.CheckAdminExists(adminId).GetAwaiter().GetResult())
            {
                throw new ArgumentException("此员工不存在。");
            }
            AdminEntity entity = this.adminData.GetAdmin(adminId).GetAwaiter().GetResult();
            if (!string.IsNullOrWhiteSpace(dto.Password))
            {
                if (dto.Password.Length < 8 || dto.Password.Length > 16)
                {
                    throw new ArgumentException("长度为 8 到 16 个字符。");
                }
                Regex regex = new Regex(RegexPatterns.PASSWORD);
                if (!regex.IsMatch(dto.Password))
                {
                    throw new ArgumentException("密码需包含字母和数字。");
                }
                entity.Password = dto.Password.SHA256(entity.LoginName);
            }
            entity.FullName = dto.FullName;
            if (!string.IsNullOrWhiteSpace(dto.Avatar))
            {
                entity.Avatar = dto.Avatar;
            }
            return this.adminData.UpdateAdminFullNameAndPassword(entity).GetAwaiter().GetResult();
        }
        
        public AdminDto SetAdminAccountStatus(long adminId, AccountStatus accountStatus)
        {
            if (!this.adminData.CheckAdminExists(adminId).GetAwaiter().GetResult())
            {
                throw new ArgumentException("此员工不存在。");
            }
            if (this.companyData.CheckCompanyHeadExists(adminId).GetAwaiter().GetResult())
            {
                throw new ArgumentException("此账号为公司负责人，请先更换公司负责人后再进行删除。");
            }
            if (this.departmentData.CheckPrincipal(adminId).GetAwaiter().GetResult())
            {
                throw new ArgumentException("此账号为部门负责人，请先更换部门负责人。");
            }
            var entity = adminData.SetAdminAccountStatus(adminId, accountStatus).GetAwaiter().GetResult();
            if (entity == null)
            {
                return null;
            }
            if(accountStatus == AccountStatus.Deleted)
            {
                var staffMappingList = this.staffOrganizationMappingRecordData.GetList(adminId).GetAwaiter().GetResult();
                foreach(var staff in staffMappingList)
                {
                    var department = this.departmentData.GetById(staff.DepartmentId).GetAwaiter().GetResult();
                    if (this.staffOrganizationMappingRecordData.Delete(staff.StaffOrganizationMappingRecordId).GetAwaiter().GetResult())
                    {
                        string[] path = department.DepartmentPath.IndexOf(",") > -1 ? department.DepartmentPath.Split(',') : new string[] { department.DepartmentPath };
                        int i = 0;
                        foreach (string item in path)
                        {
                            if (i > 0)
                            {
                                int id = Convert.ToInt32(item);
                                if (id > 0)
                                {
                                    this.departmentData.UpdateStaffCountAsync(id).GetAwaiter().GetResult();
                                }
                            }
                            i++;
                        }
                        this.departmentData.UpdateStaffCountAsync(department.DepartmentId).GetAwaiter().GetResult();
                    }
                }
            }
            return entity.As<AdminDto>();
        }

        public bool UpdateAdminAvatar(long adminId, string avatar)
        {
            if (!this.adminData.CheckAdminExists(adminId).GetAwaiter().GetResult())
            {
                throw new ArgumentException("此员工不存在。");
            }
            AdminEntity admin = this.adminData.GetAdmin(adminId).GetAwaiter().GetResult();
            admin.Avatar = avatar;
            return adminData.UpdateAdminAvatar(admin).GetAwaiter().GetResult();
        }

        public IEnumerable<AdminDto> GetAdminsForCompany()
        {
            return this.adminData.GetAdminsForCompany().GetAwaiter().GetResult().As<IEnumerable<AdminDto>>();
        }

        public IEnumerable<AdminDto> GetCompanyAdminsAsync(int companyId)
        {
            return this.adminData.GetCompanyAdminsAsync(companyId).GetAwaiter().GetResult().As<IEnumerable<AdminDto>>();
        }
    }
}
